var KeepAlive = {
  name: 'keep-alive',
  // 抽象组件
  abstract: true,

  // 接收的参数
  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },

  // 创建缓存表
  created: function created () {
    this.cache = Object.create(null);
    this.keys = [];
  },

  destroyed: function destroyed () {
    for (var key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys);
    }
  },

  mounted: function mounted () {
    var this$1 = this;

    this.$watch('include', function (val) {
      pruneCache(this$1, function (name) { return matches(val, name); });
    });
    this.$watch('exclude', function (val) {
      pruneCache(this$1, function (name) { return !matches(val, name); });
    });
  },

  render: function render () {
    var slot = this.$slots.default;
    // 获取 `keep-alive` 包裹着的第一个子组件对象及其组件名； 
    // 如果 keep-alive 存在多个子元素，`keep-alive` 要求同时只有一个子元素被渲染。
    // 所以在开头会获取插槽内的子元素，
    // 调用 `getFirstComponentChild` 获取到第一个子元素的 `VNode`。
    var vnode = getFirstComponentChild(slot);
    var componentOptions = vnode && vnode.componentOptions;
    if (componentOptions) {
      // check pattern
      var name = getComponentName(componentOptions);
      var ref = this;
      var include = ref.include;
      var exclude = ref.exclude;
      // 根据设定的黑白名单（如果有）进行条件匹配，决定是否缓存。   
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
      // 不匹配，直接返回组件实例（`VNode`），否则开启缓存策略。
        return vnode
      }

      var ref$1 = this;
      var cache = ref$1.cache;
      var keys = ref$1.keys;
      // 根据组件ID和tag生成缓存Key
      var key = vnode.key == null
        ? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : '')
        : vnode.key;
      if (cache[key]) {
      // 并在缓存对象中查找是否已缓存过该组件实例。如果存在，直接取出缓存值
        vnode.componentInstance = cache[key].componentInstance;
        // 并更新该key在this.keys中的位置（更新key的位置是实现LRU置换策略的关键）。
        remove(keys, key);
        keys.push(key);
      } else {
       // 如果不存在，则在this.cache对象中存储该组件实例并保存key值，
        cache[key] = vnode;
        keys.push(key);
        // 之后检查缓存的实例数量是否超过max设置值，超过则根据LRU置换策略删除最近最久未使用的实例
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode);
        }
      }
		// 最后将该组件实例的keepAlive属性值设置为true。
      vnode.data.keepAlive = true;
    }
    return vnode || (slot && slot[0])
  }
};
